package com.xuyiwei.mayi.test;

import java.sql.*;
import java.util.concurrent.CountDownLatch;

/**
 * 修正版 全部执行的
 * Created by xuyiwei on 2019/4/13.
 */
public class LostUpdateOccDiscard2 implements Runnable{
    private CountDownLatch countDown;
    public LostUpdateOccDiscard2(CountDownLatch countDown){
        this.countDown = countDown;
    }

    @Override
    public void run() {
        Connection conn=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysqllock?useUnicode=true&characterEncoding=UTF-8",
                    "root", "root");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        try {
            int try_times=100;
            int count;
            int version;
            PreparedStatement ps;
            ResultSet rs;

            //把循环条件放在里面if里
            while(try_times>0){
                //开始事务
                try_times--;
                conn.setAutoCommit(false);

                //读操作
                ps=conn.prepareStatement("select * from LostUpdate where id =1");
                rs=ps.executeQuery();

                //判断事务执行的条件，首先是能执行，其次是需要执行
                if(rs.next()){
                    count= rs.getInt("count");
                    version= rs.getInt("version");

                    count++;

                    //更新操作，用cas原子操作来更新
                    ps =conn.prepareStatement("update LostUpdate set count=?, version=version+1 where id =1 and version=?");
                    ps.setInt(1, count);
                    ps.setInt(2, version);
                    int result = ps.executeUpdate();

                    //每次执行完更新操作，检测一次冲突
                    //成功，则继续事务
                    //失败，回滚，睡100ms，避开竞争。结束这次循环，开启新事务。
                    if(result==0) {
                        conn.rollback();
                        Thread.sleep(100);
                        continue;
                    }

                    //事务一路顺风，没遇到冲突，事务提交，跳出while
                    conn.commit();
                    break;
                }
                //作为while条件不成立时的处理，比如该行数据被删除。
                else{
                    conn.rollback();
                    break;
                }
            }
            if(try_times<=0) throw new Exception("冲突重试的此时过多，事务失败");
            System.out.println(try_times);
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }catch (Exception e) {
            System.out.println(e.getMessage());
        }

        //表示一次任务完成
        countDown.countDown();
    }
}
